﻿
#include "base/SimpleEvent.h"
#include <assert.h>
#include <stdio.h>

#if defined(WIN32)

#else
 #include <sys/time.h>
#include <errno.h>
#endif

namespace base
{

    SimpleEvent::SimpleEvent(bool bManualReset)
        : m_bManualReset(bManualReset)
    {
#if defined(WIN32)
        /*
        对于手动复位的（manual_reset=TRUE）的Event，当多个线程等待同一个Event时，一次SetEvent()激活所有等待线程。
        对于自动复位的（manual_reset=FALSE）的Event，当多个线程等待同一个Event时，一次SetEvent()激活一个等待线程。
        init_state指定事件对象的初始状态。如果为TRUE，初始状态为有信号状态；否则为无信号状态
        */
        m_handle = CreateEvent(NULL, bManualReset, FALSE, NULL);
        assert(m_handle != NULL);
#else
        pthread_mutex_init(&m_mutex, NULL);
        pthread_cond_init(&m_handle, NULL);
#endif
    }

    SimpleEvent::~SimpleEvent()
    {
#if defined(WIN32)
        CloseHandle(m_handle);
#else
        pthread_cond_destroy(&m_handle);
        pthread_mutex_destroy(&m_mutex);
#endif
    }

    void SimpleEvent::Set()
    {
#if defined(WIN32)
        BOOL ret = ::SetEvent(m_handle);
        assert(ret);
        ret = TRUE;
#else
        pthread_mutex_lock(&m_mutex);
        m_flag = true;

        if(m_bManualReset)
            pthread_cond_broadcast(&m_handle);
        else
            pthread_cond_signal(&m_handle);

        pthread_mutex_unlock(&m_mutex);
#endif
    }

    void SimpleEvent::Reset()
    {
#if defined(WIN32)

        if(!m_bManualReset)
        {
            printf("this is a auto event, Cann't manual reset.");
            return;
        }

        BOOL ret = ResetEvent(m_handle);
        assert(ret);
        ret = TRUE;
#else

        if(!m_bManualReset)
        {
			printf("this is a auto event, Cann't manual reset.");
            return;
        }

        pthread_mutex_lock(&m_mutex);
        m_flag = false;
        pthread_mutex_unlock(&m_mutex);
#endif
    }

    void SimpleEvent::Wait()
    {
#if defined(WIN32)
        WaitForSingleObject(m_handle, INFINITE);
#else

        do
        {
            pthread_mutex_lock(&m_mutex);

            if(!m_flag)
            {
                pthread_cond_wait(&m_handle, &m_mutex);
            }

            if(m_flag)
            {
                if(!m_bManualReset)
                {
                    m_flag = false;
                }

                pthread_mutex_unlock(&m_mutex);
                break;
            }
            else
            {
                pthread_mutex_unlock(&m_mutex);
                continue;
            }
        }
        while(true);

#endif
    }

    bool SimpleEvent::TryWait(uint32_t msec)
    {
#if defined(WIN32)

        if(WAIT_OBJECT_0 == WaitForSingleObject(m_handle, msec))
        {
            return TRUE;
        }

        return FALSE;
#else
        bool flag = false;
        pthread_mutex_lock(&m_mutex);
        flag = m_flag;

        if(!flag && msec > 0)
        {
            struct timeval tv = {};
            gettimeofday(&tv, NULL);
            tv.tv_sec += msec / 1000;
            tv.tv_usec += (msec % 1000 * 1000);
            tv.tv_sec += tv.tv_usec / 1000000;
            tv.tv_usec %= 1000000;
            struct timespec abstime = {};
            abstime.tv_sec = tv.tv_sec;
            abstime.tv_nsec = tv.tv_usec * 1000;
            int ret = 0;

            do
            {
                ret = pthread_cond_timedwait(&m_handle, &m_mutex, &abstime);
            }
            while((0 != ret) && (errno == EINTR));

            flag = m_flag;
        }

        if(!m_bManualReset)
        {
            m_flag = false;
        }

        pthread_mutex_unlock(&m_mutex);
        return flag;
#endif
    }

} // namespace base

